﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Pong_Project.Game_objects;
using Pong_Project;

namespace Pong_Project.Game_objects
{
    abstract class GameObject : ISubject //game objects is observable such that other objects can subscribe to get notifications of changes to the game object
    {
        private GameObjectIdentity identity;
        private Texture2D sprite;
        private Vector2 position, size, scale;
        private float rotation, layerDepth;
        private Rectangle rectangle;
        //List of other objects which observers this game object
        private List<IObserver> observers = new List<IObserver>();


        public GameObject(GameObjectIdentity identity, Vector2 position)
        {
            this.identity = identity;
            this.position = position;
            sprite = null;
            size.X = 0;
            size.Y = 0;
            scale.X = 1.0f;
            scale.Y = 1.0f;
            rotation = 0.0f;
            layerDepth = 0.0f;
            rectangle = NewRectangle;
            observers = new List<IObserver>(); //Create a new list which can be used to subscribe to updates of this game object
        }


        public List<IObserver> Observers
        {
            get { return observers; }
        }

        public GameObjectIdentity Identity
        {
            get { return identity; }
        }

        public Texture2D Sprite
        {
            get { return sprite; }
            set { sprite = value; size.X = sprite.Width; size.Y = sprite.Height; }
        }

        public float Width
        {
            get { return size.X * ScaleX; }
        }

        public float Height
        {
            get { return size.Y * ScaleY; }
        }

        public float ScaleX
        {
            get { return scale.X; }
            set { scale.X = value; }
        }

        public float ScaleY
        {
            get { return scale.Y; }
            set { scale.Y = value; }
        }

        public float Rotation
        {
            set { rotation = value; }
            get { return rotation; }
        }

        /// <summary>
        /// LayperDepth must have a value between 1.0f and 0.0f. Any larger or smaller values will not render the object.
        /// </summary>
        public float LayerDepth
        {
            set { layerDepth = value; }
            get { return layerDepth; }
        }

        public float PositionX
        {
            get { return position.X; }
            set { position.X = value; }
        }

        public float PositionY
        {
            get { return position.Y; }
            set { position.Y = value; }
        }

        public float Top
        {
            get { return PositionY; }
        }

        public float Left
        {
            get { return PositionX; }
        }

        public float Bottom
        {
            get { return PositionY + Height; }
        }

        public float Right
        {
            get { return PositionX + Width; }
        }

        public float MiddleX
        {
            get { return PositionX + Width / 2; }
        }

        public float MiddleY
        {
            get { return PositionY + Height / 2; }
        }

        private Color color = Color.White;
        public Color Color
        {
            get { return color; }
            set { color = value; }
        }

        public Rectangle Rectangle
        {
            get { return rectangle; }
        }

        private Rectangle NewRectangle
        {
            get { return new Rectangle((int)PositionX, (int)PositionY, (int)Width, (int)Height); }
        }

        public bool Intersects(Rectangle other)
        {
            return Rectangle.Intersects(other);
        }

        public bool Intersects(GameObject other)
        {
            return Intersects(other.Rectangle);
        }

        public virtual void Update(GameTime gameTime)
        {
            rectangle = NewRectangle;
        }

        public virtual void Draw(SpriteBatch spriteBatch)
        {
            if (sprite == null) throw new ArgumentNullException(identity.ToString() + " texture");
            spriteBatch.Draw(sprite, position, null, Color, rotation, Vector2.Zero, scale, SpriteEffects.None, layerDepth);
        }

        public abstract void Reset();

        public void RegisterObserver(IObserver observer)
        {
            observers.Add(observer);
        }

        public void UnregisterObserver(IObserver observer)
        {
            observers.Remove(observer);
        }

        public void NotifyObservers(GameTime gameTime)
        {
            //Here we simply iterate through each registered
            //observer and pass each one the current hitpoints.
            foreach (IObserver observer in observers)
            {
                observer.Update(gameTime);
            }
        }
    }
}
